package Sampling;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;

import Definitions.GraphClass;
import Definitions.NodeClass;
import Global.ConstantVariable;
import Global.GlobalClass;
import Global.ParametersClass;
import SyntheticData.syntheticDataGeneratorClass;

/*****************************************************************
* Name : Sampling
* Aim : This class aims to keep the mutual functions of the sampling methods and provide the calling method for the related Sampling class. *
*****************************************************************/
public abstract class SamplingAbstractClass implements SamplingMethodInterface {
	
	public String name;
	
	protected GraphClass currentGraph;
	protected GlobalClass global;
	
	protected double testRatio;
    protected double valRatio;
	protected double unusedRatio;
	protected double unlabeledRatio;
	protected double trainRatio;
	
	protected int[] datasetTestValTrainDistributionForThisFold;	
	protected int[] classLabelsEstimatedForThisFold;
	protected int[] actualClassLabelsForThisFold;
	
	//AS:[number of classifiers][local alpha value for the node]	
	protected double[][] localAlphaMatrixForThisFold;
	protected double[][] localAlphaMatrixForTheWholeDatasetCalculatedWithThisFold;
	
	//AS:[number of classifiers][local beta value for the node]	
	protected double[][] localBetaMatrixForThisFold;
	protected double[][] localBetaMatrixForTheWholeDatasetCalculatedWithThisFold;
	
	//AS:[number of classifiers][local alpha value for the node]
	protected double[] correlationsBwLAandAccThisFold;
	
	public ArrayList <Double> classRatiosOfTrain;
	
	
	SamplingAbstractClass(GraphClass currentGraph, GlobalClass global, double testRatio, double valRatio)
	{
		this(currentGraph, global, testRatio, valRatio, 0);
	}

	SamplingAbstractClass(GraphClass currentGraph, GlobalClass global, double testRatio, double valRatio, double unused)
	{
		this(currentGraph, global, testRatio, valRatio, unused, (1.0-(valRatio+testRatio+unused)));
	}
	SamplingAbstractClass(GraphClass currentGraph, GlobalClass global, double testRatio, double valRatio, double unused, double trainRatio)
	{
		this.testRatio = testRatio;
		this.valRatio = valRatio;
		this.unusedRatio = unused;
		this.trainRatio = trainRatio;
		this.currentGraph = currentGraph;
		this.setGlobal(global);
		datasetTestValTrainDistributionForThisFold = new int[currentGraph.getDataSet().size()];
		classLabelsEstimatedForThisFold = new int[currentGraph.getDataSet().size()];		
		actualClassLabelsForThisFold = new int [currentGraph.getDataSet().size()];
		classRatiosOfTrain = new ArrayList <Double>();
		setClassLabelsEstimatedAsMinusOne();
		setActualLabels();
	}
	
	public abstract void generateSampling(Definitions.GraphClass g);
	
	public int[] getActualClassLabelsForThisFold() 
	{
		return actualClassLabelsForThisFold;
	}
	
	public int getActualClassLabelsForSelectedNode(NodeClass node)
	{
		return actualClassLabelsForThisFold[node.getOrder()];
	}

	public void setActualClassLabelsForThisFold(int[] actualClassLabelsForThisFold) {
		this.actualClassLabelsForThisFold = actualClassLabelsForThisFold;
	}

	public void setActualClassLabelForThisFoldForSpecifiedNode(NodeClass node, int actualLabel)
	{
		int index = node.getOrder();
		actualClassLabelsForThisFold[index] = actualLabel;		
	}
	
	public void setActualLabels()
	{
		int i=0;
		
		for(NodeClass u: currentGraph.getDataSet())
		{
			actualClassLabelsForThisFold[i] = u.getClassOrder();
			i++;
		}
	}

	public void setLocalAlphaMatrixForThisFold(double[][] localAlphaMatrixForThisFold, double[][] localAlphaMatrixForTheWholeDatasetCalculatedWithThisFold)
	{
		//TODO AS BAKILACAK BUNA
		//System.arraycopy(arg0, arg1, arg2, arg3, arg4)
		this.localAlphaMatrixForThisFold = localAlphaMatrixForThisFold;
		this.localAlphaMatrixForTheWholeDatasetCalculatedWithThisFold = localAlphaMatrixForTheWholeDatasetCalculatedWithThisFold;
	}
	
	public double[][] getLocalAlphaMatrixForThisFold()
	{
		return localAlphaMatrixForThisFold;
	}
	
	public double[][] getLocalAlphaMatrixForTheWholeDatasetCalculatedWithThisFold()
	{
		return localAlphaMatrixForTheWholeDatasetCalculatedWithThisFold;
	}
	
	public void setLocalBetaMatrixForThisFold(double[][] localBetaMatrixForThisFold, double[][] localBetaMatrixForTheWholeDatasetCalculatedWithThisFold) {
		this.localBetaMatrixForThisFold = localBetaMatrixForThisFold;
		this.localBetaMatrixForTheWholeDatasetCalculatedWithThisFold = localBetaMatrixForTheWholeDatasetCalculatedWithThisFold;
	}	
	
	public double[][] getLocalBetaMatrixForThisFold() {
		return localBetaMatrixForThisFold;
	}
	
	public double[][] getLocalBetaMatrixForTheWholeDatasetCalculatedWithThisFold()
	{
		return localBetaMatrixForTheWholeDatasetCalculatedWithThisFold;
	}
	
	
	public void setCorrelationsBwLAandAccThisFold(double[] correlationsBwLAandAccThisFold)
	{
		//TODO AS BAKILACAK BUNA
		//System.arraycopy(arg0, arg1, arg2, arg3, arg4)
		this.correlationsBwLAandAccThisFold = correlationsBwLAandAccThisFold;
	}
	
	
	public double[] getCorrelationsBwLAandAccThisFold()
	{
		return correlationsBwLAandAccThisFold;
	}
	
	/*
	void setLocalAlphaOfTheNodeForThisFoldWrtClassOrder(NodeClass selectedNode, int classOrder, double localAlpha)
	{
		if(classOrder>=GlobalClass.classSize)
		{
			System.out.println("ERROR:There is no such class order:" + classOrder);
			System.exit(0);
		}		
		localAlphaMatrixForThisFold[selectedNode.getOrder()][classOrder] = localAlpha;
	}

	
	double getLocalAlphaOfTheNodeForThisFoldWrtClassOrder(NodeClass selectedNode, int classOrder)
	{
		if(classOrder>=GlobalClass.classSize)
		{
			System.out.println("ERROR:There is no such class order:" + classOrder);
			System.exit(0);
		}
		
		return localAlphaMatrixForThisFold[selectedNode.getOrder()][classOrder];
	}*/
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	
	public void addNodeToUnusedSet(NodeClass selectedNode)
	{
		datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()]=ConstantVariable.Sampling_Constants.NODE_IS_IN_UNUSED_SET_FOR_THE_FOLD;	
	}
	
	public void addNodeToTestSet(NodeClass selectedNode)
	{
		datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()]=ConstantVariable.Sampling_Constants.NODE_IS_IN_TEST_SET_FOR_THE_FOLD;	
	}
	
	public void addNodeToValidationSet(NodeClass selectedNode)
	{
		datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()]=ConstantVariable.Sampling_Constants.NODE_IS_IN_VALIDATION_SET_FOR_THE_FOLD;	
	}
	
	public void addNodeToTrainingSet(NodeClass selectedNode)
	{
		//System.out.println("add Node to training set ");
		datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()]=ConstantVariable.Sampling_Constants.NODE_IS_IN_TRAINING_SET_FOR_THE_FOLD;	
	}

	public void addNodeToUnlabeledSet(NodeClass selectedNode)
	{
		//System.out.println("add Node to training set ");
		datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()]=ConstantVariable.Sampling_Constants.NODE_IS_IN_UNLABELED_SET_FOR_THE_FOLD;	
	}
	
	public void setAllTheGraphAsTrainingSetForDebuggingPurposes()
	{
		for(int i=0; i<datasetTestValTrainDistributionForThisFold.length; i++)
			datasetTestValTrainDistributionForThisFold[i]=ConstantVariable.Sampling_Constants.NODE_IS_IN_TRAINING_SET_FOR_THE_FOLD;		
	}
	
	public void setAllTheGraphAsTestSetForDebuggingPurposes()
	{
		for(int i=0; i<datasetTestValTrainDistributionForThisFold.length; i++)
			datasetTestValTrainDistributionForThisFold[i]=ConstantVariable.Sampling_Constants.NODE_IS_IN_TEST_SET_FOR_THE_FOLD;		
	}
	
	public void initializeTestTrainValidationAssignmentsForTheFold()
	{
		Arrays.fill(datasetTestValTrainDistributionForThisFold, ConstantVariable.Sampling_Constants.NODE_IS_NOT_ASSIGNED_YET_TO_ANY_SET_FOR_THE_FOLD);				
	}
	/*AS START*/
	public boolean isTheAssignmentOfTheNodeForThisFoldDone(NodeClass selectedNode)
	{
		return datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()] == ConstantVariable.Sampling_Constants.NODE_IS_NOT_ASSIGNED_YET_TO_ANY_SET_FOR_THE_FOLD;	
	}
	
	public boolean isTheNodeInUnusedForThisFold(NodeClass selectedNode)
	{
		return datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()] == ConstantVariable.Sampling_Constants.NODE_IS_IN_UNUSED_SET_FOR_THE_FOLD;
	}
	
	public boolean isTheNodeInTrainingSetForTheFold(NodeClass selectedNode) 
	{
		return datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()] == ConstantVariable.Sampling_Constants.NODE_IS_IN_TRAINING_SET_FOR_THE_FOLD;
	}
	
	public boolean isTheNodeInValidationSetForTheFold(NodeClass selectedNode) 
	{
		return datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()] == ConstantVariable.Sampling_Constants.NODE_IS_IN_VALIDATION_SET_FOR_THE_FOLD;
	}
	
	public boolean isTheNodeInTestSetForTheFold(NodeClass selectedNode) 
	{
		return datasetTestValTrainDistributionForThisFold[selectedNode.getOrder()] == ConstantVariable.Sampling_Constants.NODE_IS_IN_TEST_SET_FOR_THE_FOLD;
	}
	
	/*****************************************************************
	* Name : getTestNodes
	* Aim : This method aims to return the nodes that are labelled as test nodes*
	* Inputs : - *
	* Outputs :  ArrayList<Node> *
	* Data Structures : *
	* Algorithms : This method checks every node in the dataset and if the node is a test node it adds this node to return list *
	*****************************************************************/
	public ArrayList<NodeClass> getTestNodes() 
	{
		/* nodeSet to keep the labeled nodes */
		ArrayList<NodeClass> g = new ArrayList<NodeClass>();
		ArrayList<NodeClass> datasetOfTheGraph = currentGraph.getDataSet();
	
		/* Find the test nodes and add to g */
		for (int i = 0; i < datasetTestValTrainDistributionForThisFold.length; i++) 
		{
			if (datasetTestValTrainDistributionForThisFold[i]==ConstantVariable.Sampling_Constants.NODE_IS_IN_TEST_SET_FOR_THE_FOLD) 
			{
				g.add(datasetOfTheGraph.get(i));
			}
		}
		return g;
	}
	
	/*****************************************************************
	* Name : getValNodes
	* Aim : This method aims to return the nodes that are labelled as validation nodes*
	* Inputs : - *
	* Outputs :  ArrayList<Node> *
	* Data Structures : *
	* Algorithms : This method checks every node in the dataset and if the node is a validation node it adds this node to return list *
	*****************************************************************/
	public ArrayList<NodeClass> getValNodes()
	{
		// nodeSet to keep the unlabelled nodes 
		ArrayList<NodeClass> g = new ArrayList<NodeClass>();
		ArrayList<NodeClass> datasetOfTheGraph = currentGraph.getDataSet();
		
		// Find the validation nodes and add to g 
		for (int i = 0; i < datasetTestValTrainDistributionForThisFold.length; i++)
		{
			if (datasetTestValTrainDistributionForThisFold[i]==ConstantVariable.Sampling_Constants.NODE_IS_IN_VALIDATION_SET_FOR_THE_FOLD) 
			{
				g.add(datasetOfTheGraph.get(i));
			}
		}
		return g;
	}
	
	/*****************************************************************
	* Name : getTrainNodes
	* Aim : This method aims to return the nodes that are labelled as train nodes*
	* Inputs : - *
	* Outputs :  ArrayList<Node> *
	* Data Structures : *
	* Algorithms : This method checks every node in the dataset and if the node is a train node it adds this node to return list *
	*****************************************************************/

	public ArrayList<NodeClass> getTrainNodes() 
	{
		/* nodeSet to keep the unlabeled nodes */
		ArrayList<NodeClass> g = new ArrayList<NodeClass>();
		ArrayList<NodeClass> datasetOfTheGraph = currentGraph.getDataSet();

		/* Find the train nodes and add to g */
		for (int i = 0; i < datasetTestValTrainDistributionForThisFold.length; i++) 
		{
			if (datasetTestValTrainDistributionForThisFold[i]==ConstantVariable.Sampling_Constants.NODE_IS_IN_TRAINING_SET_FOR_THE_FOLD) 
			{
				g.add(datasetOfTheGraph.get(i));
			}
		}
		return g;
	}

	/*****************************************************************
	* Name : getTrainNodes
	* Aim : This method aims to return the nodes that are labelled as train nodes*
	* Inputs : - *
	* Outputs :  ArrayList<Node> *
	* Data Structures : *
	* Algorithms : This method checks every node in the dataset and if the node is a train node it adds this node to return list *
	*****************************************************************/

	public ArrayList<NodeClass> getUnusedNodes() 
	{
		/* nodeSet to keep the unlabeled nodes */
		ArrayList<NodeClass> g = new ArrayList<NodeClass>();
		ArrayList<NodeClass> datasetOfTheGraph = currentGraph.getDataSet();

		/* Find the train nodes and add to g */
		for (int i = 0; i < datasetTestValTrainDistributionForThisFold.length; i++) 
		{
			if (datasetTestValTrainDistributionForThisFold[i]==ConstantVariable.Sampling_Constants.NODE_IS_IN_UNUSED_SET_FOR_THE_FOLD) 
			{
				g.add(datasetOfTheGraph.get(i));
			}
		}
		return g;
	}

	
		/*****************************************************************
	* Name : getUnlabeledNodes
	* Aim : This method aims to return the nodes that are labelled as test nodes*
	* Inputs : - *
	* Outputs :  ArrayList<Node> *
	* Data Structures : *
	* Algorithms : This method checks every node in the dataset and if the node is a test node it adds this node to return list *
	*****************************************************************/
	public ArrayList<NodeClass> getUnlabeledNodes() 
	{
		/* nodeSet to keep the labeled nodes */
		ArrayList<NodeClass> g = new ArrayList<NodeClass>();
		ArrayList<NodeClass> datasetOfTheGraph = currentGraph.getDataSet();
	
		/* Find the test nodes and add to g */
		for (int i = 0; i < datasetTestValTrainDistributionForThisFold.length; i++) 
		{
			if (datasetTestValTrainDistributionForThisFold[i]==ConstantVariable.Sampling_Constants.NODE_IS_IN_UNLABELED_SET_FOR_THE_FOLD) 
			{
				g.add(datasetOfTheGraph.get(i));
			}
		}
		return g;
	}
	
	/*****************************************************************
	* Name : getTrainNodes
	* Aim : This method aims to return the nodes that are labelled as train nodes*
	* Inputs : - *
	* Outputs :  ArrayList<Node> *
	* Data Structures : *
	* Algorithms : This method checks every node in the dataset and if the node is a train node it adds this node to return list *
	*****************************************************************/

	public ArrayList<NodeClass> getTrainAndValNodes() 
	{
		/* nodeSet to keep the unlabeled nodes */
		ArrayList<NodeClass> g = new ArrayList<NodeClass>();
		ArrayList<NodeClass> datasetOfTheGraph = currentGraph.getDataSet();

		/* Find the train nodes and add to g */
		for (int i = 0; i < datasetTestValTrainDistributionForThisFold.length; i++) 
		{
			if (datasetTestValTrainDistributionForThisFold[i]==ConstantVariable.Sampling_Constants.NODE_IS_IN_TRAINING_SET_FOR_THE_FOLD
					|| datasetTestValTrainDistributionForThisFold[i]==ConstantVariable.Sampling_Constants.NODE_IS_IN_VALIDATION_SET_FOR_THE_FOLD) 
			{
				g.add(datasetOfTheGraph.get(i));
			}
		}
		return g;
	}
	
	/*****************************************************************
	* Name : getNotAssignedNodes
	* Aim : This method aims to return the nodes that still not assigned to any of the training, test or validation sets.*
	* Inputs : - *
	* Outputs :  ArrayList<Node> *
	* Data Structures : *
	* Algorithms : This method checks every node in the dataset and if the node is a test node it adds this node to return list *
	*****************************************************************/
	public ArrayList<NodeClass> getNotAssignedNodes() 
	{
		/* nodeSet to keep the labeled nodes */
		ArrayList<NodeClass> g = new ArrayList<NodeClass>();
		ArrayList<NodeClass> datasetOfTheGraph = currentGraph.getDataSet();
	
		/* Find the test nodes and add to g */
		for (int i = 0; i < datasetTestValTrainDistributionForThisFold.length; i++) 
		{
			if (datasetTestValTrainDistributionForThisFold[i]==ConstantVariable.Sampling_Constants.NODE_IS_NOT_ASSIGNED_YET_TO_ANY_SET_FOR_THE_FOLD) 
			{
				g.add(datasetOfTheGraph.get(i));
			}
		}
		return g;
	}
	/*----------------------------------------------------------------------------------*/
	public int getClassLabelEstimated(NodeClass selectedNode)
	{
		return classLabelsEstimatedForThisFold[selectedNode.getOrder()];		
	}
	
	/****************************************************************
	* Name : setClassLabelsEstimatedAsMinusOne
	* Aim : To assign -1 to each node's estimated class label so that it resets the CCA algorithm's work.
	* Inputs : 
	* Outputs :  void *
	* Data Structures : *
	* Algorithms : --
	*****************************************************************/
	public void setClassLabelsEstimatedAsMinusOne() 
	{
		Arrays.fill(classLabelsEstimatedForThisFold, ConstantVariable.Common_ConstantVariables.ESTIMETED_CLASS_LABEL_IS_NOT_ASSIGNED_YET);		
	}
	
	public void setClassLabelEstimated(NodeClass selectedNode, int classLabelEstimated) 
	{
		classLabelsEstimatedForThisFold[selectedNode.getOrder()] = classLabelEstimated;		
	}
	
	/*****************************************************************
	* Name : getSamplingResult
	* Aim : This method aims to get the related sampling operation's result and print
	* each val, train and test nodes and control them.
	* Inputs : - *
	* Outputs :  - *
	* Data Structures : *
	* Algorithms : - *
	*****************************************************************/
	public void getSamplingResult() 
	{
		
		ArrayList<Integer> results = new ArrayList<Integer>();
		ArrayList<Integer> results1 = new ArrayList<Integer>();
		ArrayList<Integer> results2 = new ArrayList<Integer>();
		
		ArrayList<NodeClass> dataSet = currentGraph.getDataSet();
		
		System.out.println("Sampling Result inside graph  class size:  " + getGlobal().classList.size() + "  data size:"+ dataSet.size());
		
		for (int i = 0; i < getGlobal().classList.size(); i++) 
		{
			results.add(0);
			results1.add(0);
			results2.add(0);
		}
		
		for (int i = 0; i < dataSet.size(); i++) 
		{
			if(isTheNodeInTestSetForTheFold(dataSet.get(i)))
				results.set(dataSet.get(i).getClassOrder(), results.get(dataSet
						.get(i).getClassOrder()) + 1);
			if(isTheNodeInValidationSetForTheFold(dataSet.get(i)))
				results1.set(dataSet.get(i).getClassOrder(), results1
						.get(dataSet.get(i).getClassOrder()) + 1);
			if((isTheNodeInTrainingSetForTheFold(dataSet.get(i))))
				results2.set(dataSet.get(i).getClassOrder(), results2
						.get(dataSet.get(i).getClassOrder()) + 1);
		}

		for (int i = 0; i < getGlobal().classList.size(); i++)
			System.out.println("*" + getGlobal().classList.get(i).getRatio()
					+ "  Tot:" + getGlobal().classList.get(i).getRatio()
					* dataSet.size() + "  Test:" + results.get(i) + "  Tr: "
					+ results2.get(i) + "  val: " + results1.get(i));

	}
	
	/*****************************************************************
	* Name : writeFolds
	* Aim : This method is used to write the folds in each sampling
	* Inputs : - *
	* Outputs :  - *
	* Data Structures : *
	* Algorithms : - *
	*****************************************************************/
	public void writeFolds(int foldNo) 
	{

		try{
			String datasetName =ConstantVariable.DataSet_Constants.DATASET_NAMES[GlobalClass.RunningValues.executionFor];
			String fileAdditionalProperties  = "";
		/*
			if(GlobalClass.RunningValues.executionFor==ConstantVariable.DataSet_Constants.SYNTETIC_DATASET)
				fileAdditionalProperties="Sampling"+ParametersClass.typeOfSampling+"ms-"+syntheticDataGeneratorClass.getNumberOfSharedBits()+"Data-"+datasetName+"-Fold-"+foldNo;
			else
				fileAdditionalProperties="Sampling"+ParametersClass.typeOfSampling+"Data-"+datasetName+"-Fold-"+foldNo;
			*/
			
			FileWriter fstream = new FileWriter(fileAdditionalProperties);
		    BufferedWriter out = new BufferedWriter(fstream);

		ArrayList<NodeClass> testList = this.getTestNodes();
		ArrayList<NodeClass> trainList = this.getTrainNodes();
		ArrayList<NodeClass> valList = this.getValNodes();
		out.newLine();
		out.write("Test : ");
		out.newLine();
		for(int i = 0; i < testList.size(); i++)
		{
			out.write((testList.get(i).getOrder()+1) + "-");
		
		}
		
		out.newLine();
		
		out.write("Val: ");
		out.newLine();
		for(int i = 0; i < valList.size(); i++)
		{
			out.write((valList.get(i).getOrder()+1) + "-");
		}
		out.newLine();
		out.write("Train : ");
		out.newLine();
		for(int i = 0; i < trainList.size(); i++)
		{
			out.write((trainList.get(i).getOrder()+1) + "-");
		
		}
		out.newLine();
		out.close();
		 }catch (Exception e){//Catch exception if any
			      System.err.println("Error: " + e.getMessage());
		 }
	}


	/*****************************************************************
	* Name : shuffle
	* Aim : This method aims to change the order of the given array in a random manner. *
	* Inputs : ArrayList <Integer> nodeIdList *
	* Outputs :  - *
	* Data Structures : *
	* Algorithms : - *
	*****************************************************************/
	public void  shuffle(ArrayList <Integer> nodeIdList) 
	{	
		Random random = new Random();
		int size = nodeIdList.size();
		
		for(int i = 0; i < size; i++)
		{
			//find node order randomly
			int index1 = random.nextInt(size);
			int index2 = random.nextInt(size);
			int temp = nodeIdList.get(index1);
			//swapping the nodes which are found randomly 
			nodeIdList.set(index1, nodeIdList.get(index2));
			nodeIdList.set(index2 ,temp);
		}
	}
	
	public void setClassRatiosWithTrain(GraphClass g)
	{
		
		int classOrder;
		int size=getTrainNodes().size()+ getValNodes().size(); 
		for(int i=0; i< getGlobal().classList.size(); i++)
		{
			classRatiosOfTrain.add(i,(double)0);
		}
		
		for(int i=0; i<getTrainNodes().size() ; i++)
		{
			classOrder= getTrainNodes().get(i).getClassOrder();
			classRatiosOfTrain.set(classOrder, classRatiosOfTrain.get(classOrder)+1);
		}
		for(int i=0; i<getValNodes().size() ; i++)
		{
			classOrder= getValNodes().get(i).getClassOrder();
			classRatiosOfTrain.set(classOrder, classRatiosOfTrain.get(classOrder)+1);
		}
		
		for(int i=0; i< getGlobal().classList.size(); i++)
		{
			classRatiosOfTrain.set(i, classRatiosOfTrain.get(i)/size);
		}
	}


	
	/*****************************************************************
	* Name : Sampling
	* Aim : This method aims to call the related sampling method that corresponds to user's choice
	* Inputs : int i, double testRatio, double valRatio, double threshold, int edgeType *
	* Outputs :  - *
	* Data Structures : *
	* Algorithms : for i = 0, it calls Random Sampling, for i = 1 it calls Snowball Sampling 
	 * @throws Exception *
	*****************************************************************/

	/*****************************************************************
	* Name : getValidationError
	* Aim : This method aims to return the error rate for the label assignments to validation nodes.
	* Inputs : - *
	* Outputs :  double *
	* Data Structures : *
	* Algorithms : - *
	*****************************************************************/
	//TODO AS:Result dami olmali bakilacak.
	public double getValidationError() 
	{
		int valNode = 0;
		int validAssign = 0;
		ArrayList<NodeClass> dataSet=currentGraph.getDataSet();		
		double k;
		
		for (int j = 0; j < dataSet.size(); j++) 
		{
			if (isTheNodeInTrainingSetForTheFold(dataSet.get(j)) && isTheNodeInValidationSetForTheFold(dataSet.get(j))) 
			{
				valNode++;
				if (dataSet.get(j).getClassOrder() == getClassLabelEstimated(dataSet.get(j)))
				{
					validAssign++;	
				}
			}
		}
		if (valNode == 1)
		{
			return 0;
		}

		k = Double.parseDouble(Integer.toString(validAssign))
				/ Double.parseDouble(Integer.toString(valNode));
		return k;
	}
	
	
	//If the node whose neighbors are needed to be found in Training or validation set, 
	//then return all the neighbours of the node which are in the Training or validation set.
	
	//If the node whose neighbors are needed to be found in Test set, 
	//then return all the neighbours of the node .
	
	public ArrayList<NodeClass> findNeighbours(NodeClass selectedNode, int nodesFold, int edgeType, int neighborDegree)
	{		
		ArrayList<NodeClass> neighbourList= new ArrayList<NodeClass> ();
		ArrayList<NodeClass> neighbours= selectedNode.getNeighbours(edgeType, neighborDegree);
		if(nodesFold == ConstantVariable.Sampling_Constants.NODE_IS_IN_TRAINING_SET_FOR_THE_FOLD || nodesFold == ConstantVariable.Sampling_Constants.NODE_IS_IN_VALIDATION_SET_FOR_THE_FOLD)
		{
			for(int m=0; m<neighbours.size(); m++)
			{
				if(isTheNodeInTrainingSetForTheFold(neighbours.get(m)) || isTheNodeInValidationSetForTheFold(neighbours.get(m)))
				{
					neighbourList.add(neighbours.get(m));
				}
			}

			return neighbourList;
		}
		//all nodes are used
		if(nodesFold == ConstantVariable.Sampling_Constants.NODE_IS_IN_TEST_SET_FOR_THE_FOLD) 
		{	
			for(int m=0; m<neighbours.size(); m++)
			{
					neighbourList.add(neighbours.get(m));
			}
			return neighbourList;
		}		
		
		System.out.println("Wrong parametres in  find Neighbour "+ nodesFold ) ;		
		return null;	
	}	

	/*****************************************************************
	* Name : ResultOfTrain
	* Aim : This method aims to return the error rate for the label assignments to validation nodes.
	* Inputs : - *
	* Outputs :  double *
	* Data Structures : *
	* Algorithms : - *
	*****************************************************************/
	public double ResultOfTrain()
	{
		int testNode=0;
		int validAssign=0;  
		double k;
		ArrayList<NodeClass> datasetOfTheGraph = currentGraph.getDataSet();
		
		
		for(int j=0; j<datasetOfTheGraph.size(); j++)
		{
			if(isTheNodeInTestSetForTheFold(datasetOfTheGraph.get(j)))
			{
				testNode++;
				if(datasetOfTheGraph.get(j).getClassOrder()== getClassLabelEstimated(datasetOfTheGraph.get(j)))
				validAssign++;
			}
				
		}
		if(testNode ==0)
		{
			System.out.print("valid : "+validAssign +" test: " + testNode);
			return 0;
		}
		k= Double.parseDouble(Integer.toString(validAssign)) / Double.parseDouble(Integer.toString(testNode));
		System.out.print("valid : "+validAssign +" test: " + testNode);
			return k;
	}
	
	/*****************************************************************
	* Name : shuffle
	* Aim : This method aims to change the order of the given array in a random manner and is
	* 		used in k-fold random sampling. *
	* Inputs : ArrayList <Integer> nodeIdList, int seed *
	* Outputs :  - *
	* Data Structures : *
	* Algorithms : The difference with the other shuffle method is the seed parameter only. *
	*****************************************************************/
	public void  shuffle(ArrayList <Integer> nodeIdList, int seed) 
	{	
		Random random = new Random();
		random.setSeed(seed);
		int size = nodeIdList.size();
		
		for(int i = 0; i < size; i++)
		{
			//find node order randomly
			int index1 = random.nextInt(size);
			int index2 = random.nextInt(size);
			int temp = nodeIdList.get(index1);
			//swapping the nodes which are found randomly 
			nodeIdList.set(index1, nodeIdList.get(index2));
			nodeIdList.set(index2 ,temp);
		}
	}

	@Override
	public void generateSampling(GraphClass g, int fold) {
		// TODO Auto-generated method stub
		
	}
	
	public ArrayList<NodeClass> getNeighboursOfTheNodeWrtStage(NodeClass selectedNode, int edgeType, int neighbourHoodLevel, int stage)
	{
		ArrayList<NodeClass> allNeighboursOfTheNode;
		ArrayList<NodeClass> selectedNeighboursOfTheNode;
		
		selectedNeighboursOfTheNode = new ArrayList<NodeClass>();
		
		allNeighboursOfTheNode = selectedNode.getNeighbours(edgeType, neighbourHoodLevel);
		
		for(NodeClass i : allNeighboursOfTheNode)
		{
			if(datasetTestValTrainDistributionForThisFold[i.getOrder()]==stage)
				selectedNeighboursOfTheNode.add(i);				
		}
		
		return selectedNeighboursOfTheNode;		
	}
	
	public ArrayList<NodeClass> getNeighboursOfTheNodeWrtStageInANotManner(NodeClass selectedNode, int edgeType, int neighbourHoodLevel, int stage)
	{
		ArrayList<NodeClass> allNeighboursOfTheNode;
		ArrayList<NodeClass> selectedNeighboursOfTheNode;
		
		selectedNeighboursOfTheNode = new ArrayList<NodeClass>();
		
		allNeighboursOfTheNode = selectedNode.getNeighbours(edgeType, neighbourHoodLevel);
		
		for(NodeClass i : allNeighboursOfTheNode)
		{
			if(datasetTestValTrainDistributionForThisFold[i.getOrder()]!=stage)
				selectedNeighboursOfTheNode.add(i);				
		}
		
		return selectedNeighboursOfTheNode;		
	}

	public void setGlobal(GlobalClass global) {
		this.global = global;
	}

	public GlobalClass getGlobal() {
		return global;
	}
	
}
